/*
* @Author: chenggh
* @Date: 2025-06-13
* @link: https://oj.haizeix.com/problem/48
*/
#include <iostream>
using namespace std;
int dp[100005] = {0};
int N, V;
int main(){
	cin >> N >> V;
	for(int i = 1, c, v; i <= N; i++){
		cin >> c >> v;
		// 0-1 背包学到的倒向刷表
		// for(int j = V; j >= 1; j--){
		// 	int temp_max = dp[j];
		// 	int n = 1;
		// 	while(n * c <= j){
		// 		temp_max = max(temp_max, dp[j - n * c] + n * v);
		// 		n++;
		// 	}
		// 	dp[j] = temp_max;
		// }

		// 这里可以是正向刷表，0-1背包修改刷表顺序就是完全背包
		// 因为我们期待，在dp[i][j]更新前dp[i][j]也已经更新 -> 依赖
		// 而之前，我们害怕在对dp[i][j]更新前对dp[i - 1][j]进行更新 |v 依赖
		for(int j = c; j <= V; j++){
			dp[j] = max(dp[j], dp[j - c] + v);
		}
	}
	// 两个方向都对，但是反向更加耗时
	cout << dp[V] << endl;
	return 0;
}